/**
 * @file dns_server.cc
 * @brief DNS服务器实现文件
 * 
 * 实现简单的DNS服务器功能，用于强制门户：
 * - 监听53端口的DNS查询
 * - 将所有查询重定向到配置页面IP
 * - 支持强制门户检测
 * 
 * @author SiaZhang
 * @version 2.4.2
 */

#include "dns_server.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_log.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>

#define TAG "DnsServer"      ///< 日志标签

/**
 * @brief 构造函数
 * 
 * 初始化DNS服务器，设置默认状态
 */
DnsServer::DnsServer() {
}

/**
 * @brief 析构函数
 * 
 * 清理DNS服务器资源
 */
DnsServer::~DnsServer() {
}

/**
 * @brief 启动DNS服务器
 * 
 * @param gateway 网关IP地址，DNS查询将重定向到此地址
 * 
 * 启动流程：
 * 1. 创建UDP套接字
 * 2. 绑定到53端口（标准DNS端口）
 * 3. 创建处理任务
 */
void DnsServer::Start(esp_ip4_addr_t gateway) {
    ESP_LOGI(TAG, "Starting DNS server");
    gateway_ = gateway;

    // 创建UDP套接字
    fd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (fd_ < 0) {
        ESP_LOGE(TAG, "Failed to create socket");
        return;
    }

    // 配置服务器地址结构
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);    // 监听所有接口
    server_addr.sin_port = htons(port_);                // DNS标准端口53

    // 绑定套接字到指定端口
    if (bind(fd_, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        ESP_LOGE(TAG, "failed to bind port %d", port_);
        close(fd_);
        return;
    }

    // 创建DNS处理任务
    xTaskCreate([](void* arg) {
        DnsServer* dns_server = static_cast<DnsServer*>(arg);
        dns_server->Run();
    }, "DnsServerTask", 4096, this, 5, NULL);
}

/**
 * @brief 停止DNS服务器
 * 
 * 停止DNS服务并清理资源
 */
void DnsServer::Stop() {
    ESP_LOGI(TAG, "Stopping DNS server");
    // TODO: 实现完整的停止逻辑
    // 需要添加任务停止标志和套接字关闭
}

/**
 * @brief DNS服务主循环
 * 
 * 在独立任务中运行，处理DNS查询请求：
 * 1. 接收DNS查询数据包
 * 2. 构造简单的DNS响应
 * 3. 将所有查询重定向到网关IP
 * 4. 发送响应给客户端
 */
void DnsServer::Run() {
    char buffer[512];   // DNS数据包缓冲区
    
    while (1) {
        struct sockaddr_in client_addr;
        socklen_t client_addr_len = sizeof(client_addr);
        
        // 接收DNS查询数据包
        int len = recvfrom(fd_, buffer, sizeof(buffer), 0, 
                          (struct sockaddr *)&client_addr, &client_addr_len);
        if (len < 0) {
            ESP_LOGE(TAG, "recvfrom failed, errno=%d", errno);
            continue;
        }

        // 构造简单的DNS响应（将所有查询指向网关）
        // 设置响应标志位
        buffer[2] |= 0x80;  // QR位：响应标志
        buffer[3] |= 0x80;  // RA位：递归可用标志
        buffer[7] = 1;      // ANCOUNT：应答记录数为1

        // 添加应答部分（Answer Section）
        memcpy(&buffer[len], "\xc0\x0c", 2);  // 名称指针（压缩格式）
        len += 2;
        
        // 添加资源记录头部
        // Type: A (IPv4地址), Class: IN, TTL: 28秒, Data Length: 4字节
        memcpy(&buffer[len], "\x00\x01\x00\x01\x00\x00\x00\x1c\x00\x04", 10);
        len += 10;
        
        // 添加IP地址数据（网关地址）
        memcpy(&buffer[len], &gateway_.addr, 4);
        len += 4;
        
        ESP_LOGI(TAG, "Sending DNS response to %s", inet_ntoa(gateway_.addr));

        // 发送DNS响应给客户端
        sendto(fd_, buffer, len, 0, (struct sockaddr *)&client_addr, client_addr_len);
    }
}
